package com.huangkailong.designpattern.singleton;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Objects;

/**
 * 饿汉式单例模式实现.
 *
 * @author huangkl
 * @since 1.0.0
 */
public class HungrySingleton implements Serializable {
    private static final long serialVersionUID = 3902396839903820722L;
    private static final HungrySingleton INSTANCE = new HungrySingleton();

    private HungrySingleton() {
        // 防止反射多次创建
        if (Objects.nonNull(INSTANCE)) {
            throw new IllegalStateException("HungrySingleton 只允许被创建一次对象!");
        }
    }

    /**
     * 获取 {@link HungrySingleton} 实例.
     *
     * @return {@link HungrySingleton} 实例
     */
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }

    /**
     * 测试.
     */
    public static void main(String[] args) {
        System.out.println("对象比较结果：");
        System.out.println(HungrySingleton.getInstance() == HungrySingleton.getInstance());
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)
        ) {
            objectOutputStream.writeObject(HungrySingleton.getInstance());

            try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
                byteArrayOutputStream.toByteArray());
                 ObjectInputStream objectInputStream = new ObjectInputStream(
                     byteArrayInputStream)) {
                Object o = objectInputStream.readObject();
                System.out.println("序列化结果:");
                System.out.println(HungrySingleton.getInstance() == o);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Constructor<HungrySingleton> constructor =
                HungrySingleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解决序列化和反序列化后破坏了单例模式.
     *
     * @return {@link HungrySingleton} 实例
     */
    public Object readResolve() {
        return INSTANCE;
    }
}
